package com.neuedu.codeg;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Hill {
    private static int[][] key = {{1,2,3},{1,1,2},{0,1,2}};		//密钥矩阵
    private static int[][] fkey = {{11,2,19},{5,23,25},{20,7,17}};	//密钥逆矩阵
    private static Map<Character,Integer> map1 = new HashMap<>();
    private static Map<Integer,Character> map2 = new HashMap<>();
    private static Scanner cin = new Scanner(System.in);
    public static void main(String[] args) {
        System.out.println("明文先按三个字母一组分组，不足三个是用X代替");
        System.out.println();
        System.out.println("==========加密过程==========");
        System.out.println("密钥矩阵如下：");
        showMartrix(key);
        matches();
        System.out.println("请输入明文：" );
        String s1 = cin.nextLine();
        String format1 = format(s1);
        encode(format1);
        System.out.println("==========解密过程==========");
        System.out.println("密钥逆矩阵如下：");
        showMartrix(fkey);
        int len = format1.length();
        decode(len);
    }


    /**
     * 将字母与数字进行一一对应
     */
    private static void matches() {
        for (int i = 0; i < 26; i++) {
            map1.put((char) (i+65), i);
        }
        for (int i = 0; i < 26; i++) {
            map2.put(i,(char) (i+65));
        }

    }

    /**
     * 展示矩阵
     *
     */
    private static void showMartrix(int[][] key2) {
        for (int i = 0; i < key2.length; i++) {
            for (int j = 0; j < key2[0].length; j++) {
                System.out.print(key2[i][j]+"     ");
            }
            System.out.println();
        }

    }

    /**
     * 将小写字母转换成大写字母
     */
    private static String format(String str) {
        String regEx="[^(A-Za-z)]";  //正则表达式
        Pattern p = Pattern.compile(regEx);
        Matcher getStr = p.matcher(str);
        str = getStr.replaceAll("").trim();
        str = str.toUpperCase();
        return str;
    }

    /**
     * 加密
     */
    private static void encode(String str) {
        int len = str.length()/3;
        if(str.length()%3!=0) {
            len++;
        }
        String[] sb = new String[len];
        for (int i = 0; i < sb.length; i++) {
            sb[i]="";
        }
        int num = 0;
        int length = str.length();
        //将明文按照按照三个字母进行分组
        for (int i = 0; i < sb.length; i++) {
            for (int j = i*3; j < length; j++) {	//第i轮，应从下标i*3开始
                char c = str.charAt(j);
                sb[i] += c;
                num++;
                if(num%3 == 0) {
                    num=0;
                    break;
                }
            }
            //当不足三个字母时补X
            while(num!=0 && num<3) {
                sb[i] += "X";
                num++;
            }
        }
        System.out.print("密文为：");
        for (int i = 0; i < sb.length; i++) {
            int[] a = new int[3];
            for (int j = 0; j < sb[i].length(); j++) {
                a[j] = map1.get(sb[i].charAt(j));
            }
            int[] b = new int[3];
            for (int j = 0; j < a.length; j++) {
                b[j] = (key[j][0]*a[0]+key[j][1]*a[1]+key[j][2]*a[2])%26;
                System.out.print(map2.get(b[j]));
            }
        }
        System.out.println();
    }

    /**
     * 解密
     */
    private static void decode(int length) {
        StringBuffer sb = new StringBuffer();
        System.out.println("请输入密文：");
        String s2 = cin.nextLine();
        String format2 = format(s2);
        int len = format2.length();
        if(len%3 != 0) {
            System.out.println("密文数量必须为3的倍数，请重新输入");
            decode(length);
        }
        int i = 0;
        System.out.print("明文为：");
        while (i < len) {
            int[] a = new int[3];
            for (int j = 0; j < a.length; j++) {
                a[j] = map1.get(format2.charAt(i));
                i++;
            }
            int[] b = new int[3];
            for (int j = 0; j < a.length; j++) {
                b[j] = (fkey[j][0]*a[0]+fkey[j][1]*a[1]+fkey[j][2]*a[2])%26;
                sb.append(map2.get(b[j]));
            }
        }
        //把补充的字母"X"去掉
        String substring = sb.toString().substring(0, length);
        System.out.println(substring);
    }
}
